﻿using CPPEI.Coolzon.UI.WinForm;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace CPPEI.Coolzon.UI.ActiveXPartLib
{
    /// <summary>
    /// Interaction logic for FlashPart.xaml
    /// 调用./tools/CPPEI.Coolzon.Tools.FlashPlayTool.exe “{url}”
    /// 来显示flash
    /// </summary>
    [System.ComponentModel.DisplayName("Flash组件")]
    [XPartIcon("pack://application:,,,/CPPEI.Coolzon.UI.ActiveXPartLib;component/Images/PartIcons/FLash组件.png")]
    [XPart("FlashPart","Flash组件")]
    public partial class FlashPart : ActiveXPart
    {
        private WPFProgramWindowHost _ctlWFHost;

        #region xproperties

        [Category("Other")]
        [DisplayName("文件地址")]
        [Description("Url")]
        [Editor(typeof(XProperty.Editors.XStringEditor), typeof(XProperty.XPropertyValueEditor))]
        [XProperty(XPropertyCategory.Other, "Url", "文件地址")]
        public string XUrl
        {
            get;
            set;
        }

        #endregion

        public FlashPart()
        {
            InitializeComponent();
        }

        protected override void OnActiveXInit(PartContext context)
        {
            //InitFlash();
        }

        protected override void OnActiveXActive(PartContext context)
        {
            try
            {
                if (_ctlWFHost == null)
                {
                    //_winHost = new System.Windows.Forms.Integration.WindowsFormsHost();
                    //_ctlLayout.Children.Add(_winHost);

                    _ctlWFHost = new WPFProgramWindowHost();
                    //_activeXWrapper = new ActiveXWrapper(_ctlWFHost);
                    //_winHost.Child = _activeXWrapper;

                    //_activeXWrapper.SetContentSize(this.XWidth, this.XHeight);
                    _ctlLayout.Children.Add(_ctlWFHost);

                    string flashPlayTool = string.Format("{0}\\tools\\Flash\\CPPEI.Coolzon.Tools.FlashPlayTool.exe", AppDomain.CurrentDomain.BaseDirectory);
                    _ctlWFHost.Start(flashPlayTool, string.Format("\"{0}\"", SolutionResourceManager.GetAbsoluteFilePath(XUrl)));
                }
            }
            catch (Exception ex)
            {
                Common.Logger.ErrorToTag("UI", "Flash part:{0} OnActive Error:{1}", this.Name, ex);
            }
        }

        protected override void OnActiveXDeactive(PartContext context)
        {
            // flash组件特别占用内存，在场景非激活时释放掉内存
            if (_ctlWFHost != null)
            {
                _ctlWFHost.Stop();
                //_ctlWFHost.Dispose();
                _ctlWFHost = null;

                //_activeXWrapper.Controls.Clear();
                //_activeXWrapper.Dispose();
                //_activeXWrapper = null;

                //_winHost.Child = null;
                //_winHost.Dispose();
                //_winHost = null;

                _ctlLayout.Children.Clear();
            }
        }

        protected override void OnDestory()
        {
            if (_ctlWFHost != null)
            {
                _ctlWFHost.Stop();
                //_ctlWFHost.Dispose();
                _ctlWFHost = null;

                //_activeXWrapper.Controls.Clear();
                //_activeXWrapper.Dispose();
                //_activeXWrapper = null;

                //_winHost.Child = null;
                //_winHost.Dispose();
                //_winHost = null;

                _ctlLayout.Children.Clear();
            }
            base.OnDestory();
        }
    }
    class WPFProgramWindowHost : System.Windows.Controls.UserControl
    {
        #region 进程通讯命名管道
        string _pipeName;
        NamedPipeClientStream _pipeClient = null;
        StreamWriter _pipeClientStreamWriter = null;
        #endregion

        public struct Rect
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        [DllImport("user32.dll")]
        private static extern int GetWindowRect(IntPtr hwnd, out Rect lpRect);

        [DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId", SetLastError = true,
         CharSet = CharSet.Unicode, ExactSpelling = true,
         CallingConvention = CallingConvention.StdCall)]
        private static extern long GetWindowThreadProcessId(long hWnd, long lpdwProcessId);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern long SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
        [DllImport("user32.dll", EntryPoint = "GetWindowLongA", SetLastError = true)]
        private static extern long GetWindowLong(IntPtr hwnd, int nIndex);
        [DllImport("user32.dll", EntryPoint = "SetWindowLongA", SetLastError = true)]
        private static extern long SetWindowLong(IntPtr hwnd, int nIndex, long dwNewLong);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern long SetWindowPos(IntPtr hwnd, long hWndInsertAfter, long x, long y, long cx, long cy, long wFlags);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
        [DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]
        private static extern bool PostMessage(IntPtr hwnd, uint Msg, long wParam, long lParam);
        [DllImport("user32.dll", EntryPoint = "ShowWindow", CharSet = CharSet.Auto)]
        public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);

        private const int SWP_NOOWNERZORDER = 0x200;
        private const int SWP_NOREDRAW = 0x8;
        private const int SWP_NOZORDER = 0x4;
        private const int SWP_SHOWWINDOW = 0x0040;
        private const int WS_EX_MDICHILD = 0x40;
        private const int SWP_FRAMECHANGED = 0x20;
        private const int SWP_NOACTIVATE = 0x10;
        private const int SWP_ASYNCWINDOWPOS = 0x4000;
        private const int SWP_NOMOVE = 0x2;
        private const int SWP_NOSIZE = 0x1;
        private const int GWL_STYLE = (-16);
        private const int WS_VISIBLE = 0x10000000;
        private const int WM_CLOSE = 0x10;
        private const int WS_CHILD = 0x40000000;

        public const int SW_HIDE = 0;
        public const int SW_SHOWNORMAL = 1;
        public const int SW_SHOWMINIMIZED = 2;
        public const int SW_SHOWMAXIMIZED = 3;
        public const int SW_MAXIMIZE = 3;
        public const int SW_SHOWNOACTIVATE = 4;
        public const int SW_SHOW = 5;
        public const int SW_MINIMIZE = 6;
        public const int SW_SHOWMINNOACTIVE = 7;
        public const int SW_SHOWNA = 8;
        public const int SW_RESTORE = 9;

        IntPtr appWin;
        Process process;
        System.Windows.Forms.Timer _timer;

        System.Drawing.Point _position;
        System.Drawing.Size _size;

        public void Start(string programFile, string arguments)
        {
            ProcessStartInfo info = new ProcessStartInfo();
            info.FileName = programFile;
            info.Arguments = arguments;
            process = Process.Start(info);

            Common.Logger.DebugToTag("ui", "启动外部程序,program:{0}, arguments:{1}", programFile, arguments);

            appWin = process.MainWindowHandle;

            if (_timer != null)
            {
                _timer.Stop();
                _timer = null;
            }
            _timer = new System.Windows.Forms.Timer();
            _timer.Tick += _timer_Tick;
            _timer.Interval = 100;
            _timer.Start();
        }

        /// <summary>
        /// 用于通讯的管道名称
        /// </summary>
        /// <param name="programFile"></param>
        /// <param name="arguments"></param>
        /// <param name="pipeName"></param>
        public void Start(string programFile, string arguments, string pipeName)
        {
            // 建立命名管道
            _pipeName = pipeName;
            _pipeClient = new NamedPipeClientStream("127.0.0.1", pipeName,  PipeDirection.Out);

            ProcessStartInfo info = new ProcessStartInfo();
            info.FileName = programFile;
            info.Arguments = arguments;
            process = Process.Start(info);

            Common.Logger.DebugToTag("ui", "启动外部程序,program:{0}, arguments:{1}", programFile, arguments);

            appWin = process.MainWindowHandle;

            if (_timer != null)
            {
                _timer.Stop();
                _timer = null;
            }
            _timer = new System.Windows.Forms.Timer();
            _timer.Tick += _timer_Tick;
            _timer.Interval = 100;
            _timer.Start();
        }

        void _timer_Tick(object sender, EventArgs e)
        {
            if (appWin != IntPtr.Zero)
            {
                if (this._pipeClient != null && !this._pipeClient.IsConnected)
                {
                    try
                    {
                        this._pipeClient.Connect();
                        this._pipeClientStreamWriter = new StreamWriter(_pipeClient);
                        this._pipeClientStreamWriter.AutoFlush = true;
                        Common.Logger.DebugToTag("UI", string.Format("命名管道{0}连接成功", _pipeName));
                    }
                    catch(Exception ex)
                    {
                        Common.Logger.DebugToTag("UI", string.Format("命名管道{0}连接失败,ex:{1}", _pipeName, ex));
                        this._pipeClientStreamWriter.Close();
                        this._pipeClientStreamWriter = null;
                        this._pipeClient.Close();
                        this._pipeClient = null;
                    }
                }

                System.Windows.Point pt = this.PointToScreen(new System.Windows.Point(0, 0));
                Rect rect;
                GetWindowRect(appWin, out rect);

                int curX = (int)pt.X;
                int curY = (int)pt.Y;
                int curWidth = (int)this.ActualWidth;
                int curHeight = (int)this.ActualHeight;
                if (curX != _position.X
                    || curY != _position.Y
                    || curWidth != _size.Width
                    || curHeight != _size.Height
                    || rect.Left != curX
                    || rect.Top != curY)
                {
                    MoveWindow(appWin, curX, curY,
                        curWidth, curHeight, false);
                    //SwitchToThisWindow(appWin, true);
                    //SetWindowPos(appWin, -1, pt.X, pt.Y, this.Width, this.Height, 2);
                    Common.Logger.DebugToTag("UI", string.Format("move window, hwnd:{0}, x:{1},y:{2},w:{3},h:{4}, rect:{5},{6},{7},{8}", appWin,
                        pt.X,
                        pt.Y,
                        curWidth,
                        curHeight,
                        rect.Left,
                        rect.Top,
                        rect.Right,
                        rect.Bottom));

                    _position.X = curX;
                    _position.Y = curY;
                    _size.Width = curWidth;
                    _size.Height = curHeight;
                }
            }
            else
            {
                appWin = process.MainWindowHandle;
            }
        }

        public void Stop()
        {
            if (this._pipeClient != null)
            {
                Common.Logger.DebugToTag("UI", string.Format("关闭命名管道{0}", _pipeName));
                this._pipeClientStreamWriter.Close();
                this._pipeClientStreamWriter = null;
                this._pipeClient.Close();
                this._pipeClient = null;
            }

            if (_timer != null)
            {
                _timer.Stop();
                _timer = null;
            }
            if (process != null)
            {
                try
                {
                    process.Kill();
                }
                catch(Exception ex)
                {
                    Common.Logger.DebugToTag("UI", string.Format("关闭进程出错ex:{0}", ex));
                }
            }
        }

        public void SendCMD(string cmd)
        {
            if (this._pipeClient != null && this._pipeClient.IsConnected && this._pipeClientStreamWriter != null)
            {
                this._pipeClientStreamWriter.WriteLine(cmd);
            }
        }
    }

    class WinFormProgramWindowHost : System.Windows.Forms.Control
    {
        [DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId", SetLastError = true,
         CharSet = CharSet.Unicode, ExactSpelling = true,
         CallingConvention = CallingConvention.StdCall)]
        private static extern long GetWindowThreadProcessId(long hWnd, long lpdwProcessId);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern long SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
        [DllImport("user32.dll", EntryPoint = "GetWindowLongA", SetLastError = true)]
        private static extern long GetWindowLong(IntPtr hwnd, int nIndex);
        [DllImport("user32.dll", EntryPoint = "SetWindowLongA", SetLastError = true)]
        private static extern long SetWindowLong(IntPtr hwnd, int nIndex, long dwNewLong);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern long SetWindowPos(IntPtr hwnd, long hWndInsertAfter, long x, long y, long cx, long cy, long wFlags);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
        [DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]
        private static extern bool PostMessage(IntPtr hwnd, uint Msg, long wParam, long lParam);
        [DllImport("user32.dll", EntryPoint = "ShowWindow", CharSet = CharSet.Auto)]
        public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);

        private const int SWP_NOOWNERZORDER = 0x200;
        private const int SWP_NOREDRAW = 0x8;
        private const int SWP_NOZORDER = 0x4;
        private const int SWP_SHOWWINDOW = 0x0040;
        private const int WS_EX_MDICHILD = 0x40;
        private const int SWP_FRAMECHANGED = 0x20;
        private const int SWP_NOACTIVATE = 0x10;
        private const int SWP_ASYNCWINDOWPOS = 0x4000;
        private const int SWP_NOMOVE = 0x2;
        private const int SWP_NOSIZE = 0x1;
        private const int GWL_STYLE = (-16);
        private const int WS_VISIBLE = 0x10000000;
        private const int WM_CLOSE = 0x10;
        private const int WS_CHILD = 0x40000000;

        public const int SW_HIDE = 0;
        public const int SW_SHOWNORMAL = 1;
        public const int SW_SHOWMINIMIZED = 2;
        public const int SW_SHOWMAXIMIZED = 3;
        public const int SW_MAXIMIZE = 3;
        public const int SW_SHOWNOACTIVATE = 4;
        public const int SW_SHOW = 5;
        public const int SW_MINIMIZE = 6;
        public const int SW_SHOWMINNOACTIVE = 7;
        public const int SW_SHOWNA = 8;
        public const int SW_RESTORE = 9;

        IntPtr appWin;
        Process process;
        System.Windows.Forms.Timer _timer;

        System.Drawing.Point _position;
        System.Drawing.Size _size;

        public void Start(string programFile, string arguments)
        {
            ProcessStartInfo info = new ProcessStartInfo();
            info.FileName = programFile;
            info.Arguments = arguments;
            process = Process.Start(info);

            Common.Logger.DebugToTag("ui", "启动flash播放,program:{0}, arguments:{1}", programFile, arguments);

            appWin = process.MainWindowHandle;

            if (_timer != null)
            {
                _timer.Stop();
                _timer = null;
            }
            _timer = new System.Windows.Forms.Timer();
            _timer.Tick += _timer_Tick;
            _timer.Interval = 100;
            _timer.Start();
        }

        void _timer_Tick(object sender, EventArgs e)
        {
            if (appWin != IntPtr.Zero)
            {
                System.Drawing.Point pt = this.PointToScreen(new System.Drawing.Point(0, 0));
                if (pt.X != _position.X
                    || pt.Y != _position.Y
                    || this.Width != _size.Width
                    || this.Height != _size.Height)
                {
                    MoveWindow(appWin, pt.X, pt.Y, this.Width, this.Height, true);
                    //SwitchToThisWindow(appWin, true);
                    //SetWindowPos(appWin, -1, pt.X, pt.Y, this.Width, this.Height, 2);
                    Common.Logger.DebugToTag("UI", string.Format("move flash window, hwnd:{0}, x:{1},y:{2},w:{3},h:{4}", appWin,
                        pt.X, pt.Y,
                        (int)this.Width, (int)this.Height));

                    _position.X = pt.X;
                    _position.Y = pt.Y;
                    _size.Width = this.Width;
                    _size.Height = this.Height;
                }
            }
            else
            {
                appWin = process.MainWindowHandle;
            }
        }

        public void Stop()
        {
            if (_timer != null)
            {
                _timer.Stop();
                _timer = null;
            }
            if (process != null)
            {
                process.Kill();
            }
        }
    }
}
